/**
 * Licensed to Open-Ones Group under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Open-Ones Group licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a
 * copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package openones.ipresenter.android.view;

import java.util.Timer;
import java.util.TimerTask;

import openones.ipresenter.android.R;
import openones.ipresenter.android.blo.ConnectionSupport;
import openones.ipresenter.android.blo.TimeSupport;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Represent the Presentation screen.
 * @author OOG member
 */
public class PresentActivity extends Activity {
    /**
     * There are 1000 miliseconds in a second. Used in timer.
     */
    private static final int MILIS_IN_SECOND = 1000;
    
    /**
     * Constant indicates this connection is Bluetooth.
     */
    public static final int CONNECTION_TYPE_BLUETOOTH = 0;
    
    /**
     * Constant indicates this connection is Wifi.
     */
    public static final int CONNECTION_TYPE_WIFI = 1;
    
    /**
     * Constant indicates there is not connection.
     */
    private static final int NOT_CONNECTED = 0;
    
    /**
     * Constant indicates the current connection is OK.
     */
    private static final int CONNECTED = 1;
    
    /**
     * Constant indicates that user has not started presenting.
     */
    private static final int PRESENT_STATE_NONE = 0;
    
    /**
     * Constant indicates that user is presenting.
     */
    private static final int PRESENT_STATE_ONGOING = 1;
    
    /**
     * Constant indicates that user has paused presenting.
     * Maybe due to interupted phone call.
     */
    private static final int PRESENT_STATE_PAUSED = 2;
    
    /**
     * Constant indicate that user is in touch mode (using buttons).
     */
    private static final int PRESENT_TYPE_TOUCH = 1;
    
    /**
     * Constant indicate that user is int slide mode (using gestures).
     */
    private static final int PRESENT_TYPE_SLIDE = 2;
    
    /**
     * The TextView shows connection type (Bluetooth, Wifi).
     */
    private TextView tvConnectionType;
    
    /**
     * The EditText show the current slide number.
     */
    private EditText etSlideNumber;
    
    /**
     * Used to show the collapsed time.
     */
    private TextView tvTimer;
    
    /**
     * The current connection type (Bluetooth, Wifi).
     */
    private static int mConnectionType;
    
    /**
     * The state of the connection (not connected, connected).
     */
    private static int mConnectionState;
    
    /**
     * The current slide number. Used to update etSlideNumber.
     */
    private int mSlideNumber;
    
    /**
     * connection support.
     */
    private ConnectionSupport mConnectionSupport;
    
    /**
     * Used for controlling the timer.
     */
    private Timer mTimer;
    
    /**
     * The current present state (has not begun, on going, paused).
     * Used for controlling the timer.
     */
    private int mPresentState;
    
    /**
     * Time has passed since the first command (When user begins to present).
     */
    private int mCollapsedTime;
    
    /**
     * The current present type (touch, slide).
     */
    private int mPresentType;
    /**
     * Key code of -> = 39.
     */
    private final int NEXT = 39;
    /**
     * Key code of <- = 37.
     */
    private final int PREVIOUS = 37;
    /**
     * Key code of F5 = 116.
     */
    private final int FULLSCREEN = 116;
    /**
     * Key code of escape = 27.
     */
    private final int ENDFULLSCREEN = 27;
    
    /**
     * Called when the activity is first created.
     * @param savedInstanceState Information about the last state.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.present);
        
        setupUI();
        setupConnection();
        setupTimer();
        
        switchToPresentType(PRESENT_TYPE_TOUCH);
    }
    
    /**
     * Setup the views on the layout.
     * Set the OnClickListener for the buttons.
     */
    void setupUI() {
        Button btPrevious = (Button) findViewById(R.id.present_btPrevious);
        if (btPrevious != null) {
            btPrevious.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    sendCommandPrevious();
                	//sendCommandPrevious();
                }
            });
        }
    
        Button btNext = (Button) findViewById(R.id.present_btNext);
        if (btNext != null) {
            btNext.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    sendCommandNext();
                	//sendCommandNext();
                }
            });
        }
    
        Button btFullScreen = (Button) findViewById(R.id.present_btFullScreen);
        if (btFullScreen != null) {
            btFullScreen.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    sendCommandFullScreen();
                	//sendCommandFullScreen();
                }
            });
        }
        
        Button btExitFullScreen = (Button) findViewById(R.id.present_btExitFullScreen);
        if (btExitFullScreen != null) {
            btExitFullScreen.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    sendCommandExitFullScreen();
                	//sendCommandExitFullScreen();
                }
            });
        }
        

        Button btGo = (Button) findViewById(R.id.present_btGo);
        if (btGo != null) {
            btGo.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    sendCommandGo();
                }
            });
        }
 
        tvConnectionType = (TextView) findViewById(R.id.present_tvConnectionType);
        etSlideNumber = (EditText) findViewById(R.id.present_etSlideNumber);
        
        tvTimer = (TextView) findViewById(R.id.present_tvTimer);
        Typeface font = Typeface.createFromAsset(this.getAssets(), "fonts/digital-7 (mono).ttf");
        tvTimer.setTypeface(font);
        
        // The slideView.
        FrameLayout frame = (FrameLayout) findViewById(R.id.present_slideview);
        SlideView slideView = new SlideView(this);
        frame.addView(slideView);
    }
    
    
    /**
     * Setup connection.
     * Get intent from Scan Activity and determine whether connection type is Bluetooth or Wifi.
     * Set connection state.
     */
    void setupConnection() {
        mConnectionState = CONNECTED;
        
        try {
            Intent intent = getIntent();
            if (intent == null) {
                mConnectionState = NOT_CONNECTED;
                Toast.makeText(this, "Not connected. Intent is null", Toast.LENGTH_SHORT).show();  
                return;
            }
            Bundle bundle = intent.getExtras();
            mConnectionType = bundle.getInt("connectionType");
        } catch (Exception e) {
            mConnectionState = NOT_CONNECTED;
            mConnectionType = -1;
            Toast.makeText(this, "Not connected. Get bundle fails", Toast.LENGTH_SHORT).show();    
            return;
        }
 
        switch (mConnectionType) {
        case CONNECTION_TYPE_BLUETOOTH:
            tvConnectionType.setText("Bluetooth");
            break;
        case CONNECTION_TYPE_WIFI:
            tvConnectionType.setText("Wifi"); 
            break;
        default:
            tvConnectionType.setText("");    
            break;
        } 
        
        mConnectionSupport = new ConnectionSupport();
        if (!mConnectionSupport.setup(this, mConnectionType)) {
            mConnectionState = NOT_CONNECTED;
        }
  
    }
    
    /**
     * Switch the views according to the mPresentType.
     * @param presentType the type to switch to.
     */
    void switchToPresentType(int presentType) {
        mPresentType = presentType;
        
        // Views in Touch Mode
        Button btPrevious = (Button) findViewById(R.id.present_btPrevious);
        Button btNext = (Button) findViewById(R.id.present_btNext);
        Button btFullScreen = (Button) findViewById(R.id.present_btFullScreen);
        Button btExitFullScreen = (Button) findViewById(R.id.present_btExitFullScreen);
        Button btGo = (Button) findViewById(R.id.present_btGo);     
        TextView tvSlideNumber = (TextView) findViewById(R.id.present_tvSlideNumber);
        EditText etSlideNumber = (EditText) findViewById(R.id.present_etSlideNumber);
        
        // Views in Slide Mode
        FrameLayout frame = (FrameLayout) findViewById(R.id.present_slideview);
        
        // The Timer is displayed in both mode.
        TextView tvTimer = (TextView) findViewById(R.id.present_tvTimer);
        
        
        
        switch (mPresentType) {
        case PRESENT_TYPE_TOUCH:
            btPrevious.setVisibility(View.VISIBLE);
            btNext.setVisibility(View.VISIBLE);
            btFullScreen.setVisibility(View.VISIBLE);
            btExitFullScreen.setVisibility(View.VISIBLE);
            btGo.setVisibility(View.VISIBLE);
            tvSlideNumber.setVisibility(View.VISIBLE);
            etSlideNumber.setVisibility(View.VISIBLE);
            
            frame.setVisibility(View.INVISIBLE);
            break;
        case PRESENT_TYPE_SLIDE:
            btPrevious.setVisibility(View.INVISIBLE);
            btNext.setVisibility(View.INVISIBLE);
            btFullScreen.setVisibility(View.INVISIBLE);
            btExitFullScreen.setVisibility(View.INVISIBLE);
            btGo.setVisibility(View.INVISIBLE);
            tvSlideNumber.setVisibility(View.INVISIBLE);
            etSlideNumber.setVisibility(View.INVISIBLE);
            
            frame.setVisibility(View.VISIBLE);
            break;
        default:
            break;
        }
        
        // The timer is always displayed and brought to front.
        tvTimer.bringToFront();
        
    }
    
    
    /**
     * Send the command to the server via the OutputStream.
     * @param command The command to be sent. (type String)
     * @return boolean True if the command is sent successfully.
     */

    boolean sendCommand(String command) {
        if (mConnectionState == NOT_CONNECTED) {
            Toast.makeText(this, "Not connected.\nYou need to return to Scan Screen to connect again", 
                    Toast.LENGTH_SHORT).show();
            return false;
        }
        
        if (mConnectionSupport != null) {
            return mConnectionSupport.send(this, command);
        } else {
            return false;
        }
    
    }
    
    /**
     * Send command to server via the outputStream 
     * @param command : the command to be send ( type int)
     * @return
     */
    boolean sendCommand(int command) {
        if (mConnectionState == NOT_CONNECTED) {
            Toast.makeText(this, "Not connected.\nYou need to return to Scan Screen to connect again", 
                    Toast.LENGTH_SHORT).show();
            return false;
        }
        
        if (mConnectionSupport != null) {
            return mConnectionSupport.send(this, command);
        } else {
            return false;
        }
    
    }
    /**
     * Go to the previous slide.
     */
    void sendCommandPrevious() {
        if (sendCommand(PREVIOUS)) {
            if (mPresentState == PRESENT_STATE_NONE) {
                startTimer();
            }
            
            mSlideNumber--; 
            if (mSlideNumber < 1) {
                mSlideNumber = 1;
            }
            etSlideNumber.setText(String.valueOf(mSlideNumber));
        }
    }
    
    /**
     * Go to the next slide.
     */
    void sendCommandNext() {
        if (sendCommand(NEXT)) {
            if (mPresentState == PRESENT_STATE_NONE) {
                startTimer();
            }
            
            mSlideNumber++;
            etSlideNumber.setText(String.valueOf(mSlideNumber));
        }
    }
    
    /**
     * Enter full screen.
     */
    void sendCommandFullScreen() {
        if (sendCommand(FULLSCREEN)) {
            if (mPresentState == PRESENT_STATE_NONE) {
                startTimer();
            }
        }
    }
    
    /**
     * Exit full screen.
     */
    void sendCommandExitFullScreen() {
        if (sendCommand(ENDFULLSCREEN)) {
            if (mPresentState == PRESENT_STATE_NONE) {
                startTimer();
            }
        }
    }
    
    /**
     * Go to the slide indicated by etSlideNumber.
     */
    void sendCommandGo() {
        String strSlideNumber = (etSlideNumber.getText()).toString();
        int slideNumber;
        try {
            slideNumber = Integer.parseInt(strSlideNumber);

            if (slideNumber < 1) {
                slideNumber = 0;
            }
        } catch (Exception e) {
            slideNumber = 0;
        }
        
        if (slideNumber != 0) {   
            if (sendCommand(String.valueOf(mSlideNumber))) {
                mSlideNumber = slideNumber;
                
                if (mPresentState == PRESENT_STATE_NONE) {
                    startTimer();
                }
            }
        }
    }
    
    /**
     * Setup timer. It shows the collapses time since the first successful command of the user.
     */
    void setupTimer() {
        if (mTimer != null) {
            mTimer = null;
        }
        
        mPresentState = PRESENT_STATE_NONE;
        mCollapsedTime = 0;
        
    }
    
    /**
     * Start counting time.
     */
    void startTimer() {
        mPresentState = PRESENT_STATE_ONGOING;
        
        mTimer = new Timer();
        if (mTimer != null) {
            mTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (mPresentState == PRESENT_STATE_ONGOING) {
                        mCollapsedTime++;
                        final String timeFormat = TimeSupport.format(mCollapsedTime);
                        PresentActivity.this.runOnUiThread(new Runnable() {
                            public void run() {
                                tvTimer.setText(timeFormat);
                            }
                        });
                    }
                }
                
            }, 0, MILIS_IN_SECOND);
        }
        
    }
    
    /**
     * Stop the timer.
     * This method is call when the user has stop presenting (When user exit this activity).
     */
    void stopTimer() {
        if (mTimer != null) {
            mTimer.cancel();
            mTimer.purge();
            mTimer = null;
        }
    }
    
    /**
     * Called when the activity is about to visible.
     */
    @Override
    public void onStart() {
        super.onStart();
        if (mConnectionSupport != null && !mConnectionSupport.check()) {
            mConnectionState = NOT_CONNECTED;
        }
    }
    
    /**
     * The activity has become visible (it is now "resumed").
     */
    @Override
    public void onResume() {
        super.onResume();
        
        if (mPresentState == PRESENT_STATE_PAUSED) {
            mPresentState = PRESENT_STATE_ONGOING;
        }
    }
    
    
    /**
    * Called when the activity is stopped. It is fully invisible.
    */
    @Override
    public void onStop() {
        super.onStop();
        if (mPresentState == PRESENT_STATE_ONGOING) {
            mPresentState = PRESENT_STATE_PAUSED;
        }
    }
    
    /**
     * Called when the activity is destroyed. It is popped out from the Back Stack.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        freeResource();
    }
    
    /**
     * Create Option menu.
     * @param menu The menu to create.
     * @return boolean Indicate if the menu was created successfully.
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	super.onCreateOptionsMenu(menu);
    	menu.add(0,R.id.menu_touch,0,"touch").setIcon(android.R.drawable.ic_media_next);
    	menu.add(0,R.id.menu_slide,0, "slide").setIcon(android.R.drawable.ic_delete);
    	return true;
    }
    
    /**
     * Called when an item on the menu is selected.
     * @param item The menu item being selected.
     * @return boolean Indicate whether the OnItemClick is handled.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_scan:
            // Return to Scan Activity.
            // Connection type depends on the activity which started it.
            switch (mConnectionType) {
            case CONNECTION_TYPE_BLUETOOTH:
                // Free mConnectionSupport and stop timer
                freeResource();
                
                // Go to ScanBluetooth Activity.
                Intent intentBluetooth = new Intent(PresentActivity.this, ScanBluetoothActivity.class);
                startActivity(intentBluetooth);
                finish();
                break;
            case CONNECTION_TYPE_WIFI:
                // Free mConnectionSupport and stop timer 
                freeResource();
                
                // Go to ScanWifi Activity.
                Intent intentWifi = new Intent(PresentActivity.this, ScanWifiActivity.class);
                startActivity(intentWifi);
                finish();
                break;
            default:
                break;
            }
            return true;
        case R.id.menu_mainmenu:
            // Free mConnectionSupport and stop timer 
            freeResource();
            
            // Return to Main Menu Activity
            Intent intentMainMenu = new Intent(PresentActivity.this, MainMenuActivity.class);
            startActivity(intentMainMenu);
            finish();
            return true;
        case R.id.menu_touch:
            // Switch to touch mode
            switchToPresentType(PRESENT_TYPE_TOUCH);
            return true;
        case R.id.menu_slide:
            // Switch to slide mode
            switchToPresentType(PRESENT_TYPE_SLIDE);
            return true;
        default:
            break;
        }
        return false;
    }
    /**
     * Free any resource this Activity is using.
     */
    public void freeResource() {
        // mConnectionSupport free resource.
        if (mConnectionSupport != null) {
            mConnectionSupport.freeResource();
            
        }
        // Stop timer.
        stopTimer();
    }
}